package com.hontech.pastacooking.net

import com.hontech.pastacooking.app.NetTask
import com.hontech.pastacooking.app.log
import com.hontech.pastacooking.app.toJson

class NetClient (private val socket: NIOSocket, val info: ConnectRes) : Runnable {

    companion object {

        @Volatile
        var SELF: NetClient? = null
            private set

        fun write(req: Int, body: ByteArray) {
            SELF?.write(req, body)
        }

        fun notify(req: Int, body: ByteArray) {
            SELF?.write(req + NOTIFY_FLAG, body)
        }

        inline fun <reified T> notifyObj(req: Int, body: T) {
            val r = body.toJson()
            notify(req, r)
        }
    }

    private val readTask = object: Thread("read-task") {
        override fun run() {
            readLoop()
        }
    }

    init {
        SELF = this
        readTask.start()
        NetTask.post(this)
    }

    private var aliveFlag = true

    fun write(frame: ByteArray) {
        if (!aliveFlag) {
            return
        }
        WriteTask.write(socket, frame)
    }

    fun write(req: Int, body: ByteArray) {
        write( WriteFrame.make(req, body) )
    }

    fun blockWrite(req: Int) {
        val frame = WriteFrame.make(req)
        socket.write(frame)
    }

    fun blockWrite(req: Int, body: ByteArray) {
        socket.write( WriteFrame.make(req, body) )
    }

    override fun run() {
        if (!aliveFlag) {
            return
        }
        try {
            socket.write(WriteFrame.POLL_FRAME)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        NetTask.postDelayed(this, 5000L)
    }

    private fun readLoop() {

        while ( true ) {
            try {
                readOnce()
            } catch (e: Exception) {
                e.printStackTrace()
                break
            }
        }
        SELF = null
        aliveFlag = false
        socket.close()
        log("read loop exit")
        ConnectTask.connect(5000)
    }

    private fun readOnce() {
        val frame = socket.read()
        if (frame.isPoll()) {
            return
        }
        val task = HandlerTask(this, frame)
        NetTask.post(task)
    }
}



